package indicators

import (
	"fmt"
	"math"

	"gitee.com/lyuanbo/stock-trade/internal/pkg/mq"
	"gitee.com/lyuanbo/stock-trade/internal/pkg/stock/constant"
)

func init() {
	indicators = append(indicators, "CCI")
	Register("CCI", &Cci{})
}

type Cci struct{}

func (c *Cci) Name() string {
	return "CCI"
}

func (c *Cci) Run() {

}

func (c *Cci) ListenRealtime() {
	_ = mq.Default().Subscribe(constant.MqTopicTypeRealtime, c.Name(), func(symbol string, kline *constant.Kline) {
		fmt.Println("cci-realtime", symbol)
	})

}

func (c *Cci) ListenKline() {
	_ = mq.Default().Subscribe(constant.MqTopicTypeKline, c.Name(), func(period, symbol string) {
		fmt.Println("cci-kline", period, symbol)

	})
}

// CCI 顺势指标（Commodity Channel Index）指标通常用于衡量股票价格是否超买或超卖。
// TYP:=(HIGH+LOW+CLOSE)/3;
// CCI:(TYP-MA(TYP,N))/(0.015*AVEDEV(TYP,N));
// TYP比较容易理解，（最高价+最低价+收盘价）÷3
// MA(TYP,N) 也比较简单，就是N天的TYP的平均值
// AVEDEV(TYP,N) 比较难理解，是对TYP进行绝对平均偏差的计算。
// 也就是说N天的TYP减去MA(TYP,N)的绝对值的和的平均值。
// 表达式：
// MA = MA(TYP,N)
// AVEDEV(TYP,N) =( | 第N天的TYP - MA |   +  | 第N-1天的TYP - MA | + ...... + | 第1天的TYP - MA | ) ÷ N
// CCI = （TYP－MA）÷ AVEDEV(TYP,N)   ÷0.015
func CCI(klines []constant.Kline, period int) (values []float64) {
	for i := period - 1; i < len(klines); i++ {
		// 计算Typical Price
		tp := (klines[i].High + klines[i].Low + klines[i].Close) / 3.0

		// 计算SMA（简单移动平均）
		smaSum := 0.0
		for j := i - (period - 1); j <= i; j++ {
			// 计算周期内的典型价格之和
			smaSum += (klines[j].High + klines[j].Low + klines[j].Close) / 3.0
		}
		// 计算SMA
		sma := smaSum / float64(period)

		// 计算MAD（平均偏差）
		mdSum := 0.0
		for j := i - (period - 1); j <= i; j++ {
			// 计算周期内的典型价格与SMA之间的偏差之和
			mdSum += math.Abs(((klines[j].High + klines[j].Low + klines[j].Close) / 3.0) - sma)
		}
		// 计算平均偏差
		mad := mdSum / float64(period)

		// 计算CCI（商品通道指数）
		cci := (tp - sma) / (0.015 * mad) // 注意：修正CCI的除数为0.015

		// 四舍五入
		values = append(values, math.Round(cci*100.0)/100.0)
	}

	return values
}
